﻿/**
 * 
 * Copyright 2009 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using moose.irc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace moose.utility
{
    /// <summary>
    /// Driver Utility used to reflectively discover extensions to the 
    /// MooseIRC engine.
    /// </summary>
    /// <remarks>
    /// No longer allowing configured driver location, fornow assuming
    /// that drivers will be in our working directory.
    /// 
    /// Simplified this somewhat, but not entirely
    /// This has some issues, like if a command or an response are named the same, 
    /// or have the same trigger, im not handling it,
    /// and I suspect we could easily loose control of that whole situation.
    /// 
    /// I'm not dealint with this right now, but I suspect the issue would be resolved by 
    /// prefetching everything, and reporting errors upon initializing engine.
    /// </remarks>
    internal static class DriverUtility
    {
        /// <summary>
        /// Cached Drivers
        /// </summary>
        private static Dictionary<string, Assembly> _dictDrivers;

        /// <summary>
        /// Collection of Commands
        /// </summary>
        private static Dictionary<string, IrcAction> _dictCommands;

        /// <summary>
        /// Collection of Responses
        /// </summary>
        private static Dictionary<string, IrcAction> _dictResponses;

        /// <summary>
        /// Command Trigger XRef
        /// </summary>
        private static Dictionary<string, IrcAction> _dictCommandsXRef;

        /// <summary>
        /// Response Trigger XRef
        /// </summary>
        private static Dictionary<string, IrcAction> _dictResponsesXRef;

        /// <summary>
        /// Initialize Static Members
        /// </summary>
        static DriverUtility()
        {
            _dictDrivers = new Dictionary<string, Assembly>();
            _dictCommands = new Dictionary<string, IrcAction>();
            _dictResponses = new Dictionary<string, IrcAction>();
            _dictCommandsXRef = new Dictionary<string, IrcAction>();
            _dictResponsesXRef = new Dictionary<string, IrcAction>();
            prefetchAll();
        }

        /// <summary>
        /// Get a response action
        /// </summary>
        /// <param name="trigger">response action trigger</param>
        /// <returns>instance of response action</returns>
        internal static IrcAction getResponseAction(string trigger)
        {
            if (_dictResponsesXRef.ContainsKey(trigger))
            {
                return _dictResponsesXRef[trigger];
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Gets a command action
        /// </summary>
        /// <param name="trigger">command action trigger</param>
        /// <returns>instance of command action</returns>
        internal static IrcAction getCommandAction(string trigger)
        {
            if (_dictCommandsXRef.ContainsKey(trigger))
            {
                return _dictCommandsXRef[trigger];
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// prefetch everything
        /// </summary>
        private static void prefetchAll()
        {
            Assembly asm = null;
            object[] attributes = null;
            DriverAttribute attrib;
            foreach (string path in Directory.GetFiles(Environment.CurrentDirectory, "*.dll"))
            {
                asm = Assembly.LoadFile(path);
                attributes = asm.GetCustomAttributes(typeof(DriverAttribute), false);
                if (attributes.Length > 0)
                {
                    attrib = (DriverAttribute)attributes[0];
                    _dictDrivers[attrib.name] = asm; //cache all drivers anyways, 
                    cacheAllCommands(asm);
                    cacheAllResponses(asm);
                    
                }
            }

            return;
        }

        /// <summary>
        /// Cache all Commands
        /// </summary>
        /// <param name="driver">driver to scan for commands in</param>
        private static void cacheAllCommands(Assembly driver)
        {
            object[] attributes = null;
            IrcAction action = null;
            CommandAttribute attrib = null;
            foreach (Type typ in driver.GetTypes())
            {
                if (typ.BaseType == typeof(IrcAction))
                {
                    attributes = typ.GetCustomAttributes(typeof(CommandAttribute), false);
                    if (attributes.Length > 0)
                    {
                        attrib = (CommandAttribute)attributes[0];
                        action = (IrcAction)driver.CreateInstance(typ.ToString());
                        _dictCommands[attrib.name] = action;

                        foreach (object trigger in typ.GetCustomAttributes(typeof(TriggerAttribute), false))
                        {
                            _dictCommandsXRef[((TriggerAttribute)trigger).TriggerText] = _dictCommands[attrib.name];
                        }

                    }
                }
            }
            
            return;
        }

        /// <summary>
        /// Cache all Responses
        /// </summary>
        /// <param name="driver">driver to scan for responses in</param>
        private static void cacheAllResponses(Assembly driver)
        {
            object[] attributes = null;
            IrcAction action = null;
            ResponseAttribute attrib = null;
            foreach (Type typ in driver.GetTypes())
            {
                if (typ.BaseType == typeof(IrcAction))
                {
                    attributes = typ.GetCustomAttributes(typeof(ResponseAttribute), false);
                    if (attributes.Length > 0)
                    {
                        attrib = (ResponseAttribute)attributes[0];
                        action = (IrcAction)driver.CreateInstance(typ.ToString());
                        _dictResponses[attrib.name] = action;

                        foreach (object trigger in typ.GetCustomAttributes(typeof(TriggerAttribute), false))
                        {
                            _dictResponsesXRef[((TriggerAttribute)trigger).TriggerText] = _dictResponses[attrib.name];
                        }

                    }
                }
            }

            return;
        }

    }
}
